package ds

import (
	"time"
	"errors"
	"encoding/json"
)

type MaxQueue struct {
	strings []string
	times []time.Time
	head, tail, offset int
	full bool
}

func NewMaxQueue(n int) *MaxQueue {
	return &MaxQueue{make([]string, n), make([]time.Time, n), 0, 0, 0, false}
}

func (q *MaxQueue) MarshalJSON() (res []byte, err error) {

	entries := q.Since(0)

	res, err = json.Marshal(entries)

	return
}

func (q *MaxQueue) SinceTime(t time.Time) (entries BasicQueue) {

	for i := 0; i < q.Size(); i++ {

		j := (q.tail + i) % len(q.strings)

		if q.times[j].After(t) {
			entries = append(entries, QueueEntry{q.offset + i, q.strings[j], q.times[j]})
		}
	}

	return
}

func (q *MaxQueue) Since(pos int) (entries BasicQueue) {

	for i := 0; i < q.Size(); i++ {

		j := (q.tail + i) % len(q.strings)

		if q.offset + i > pos {
			entries = append(entries, QueueEntry{q.offset + i, q.strings[j], q.times[j]})
		}
	}

	return
}


/* returns an error if entry "i" has been forgotten */
func (q *MaxQueue) At(i int) (string, time.Time, error) {

	m := q.Size()

	if i < q.offset {
		return "", time.Time{}, errors.New("entry too old")
	}

	if m == 0 {
		panic ("maxqueue is empty")
	}

	if i > q.offset + m {
		panic ("maxqueue access out of bounds")
	}

	j := (q.tail + i - q.offset + 1) % len(q.strings)
	return q.strings[j], q.times[j], nil
}

func (q *MaxQueue) Size() int {

	if q.full {
		return len(q.strings)
	}

	return (q.head - q.tail + len(q.strings)) % (len(q.strings))
}

func (q *MaxQueue) Add(e string, at time.Time) {

	n := len(q.strings)

	if q.head == n - 1 {
		q.full = true
	}

	if q.full {
		q.tail = (q.tail + 1) % n
		q.offset++
	}

	q.head = (q.head + 1) % n

	q.strings[q.head] = e
	q.times[q.head] = at
}
